﻿var vue = null;
var lang = 'CN';
var curuser = null;
var machinetype = 'PC';
var statuslabel = null;
var browserinfo = null;
var autoresizemap = {};
var mousemovevent = null;
var logincallback = null;
var toasthidetimer = null;
var contextmenuview = null;
var singletontimermap = {};
var contextmenuattach = null;
var defaultcontextmenu = document.oncontextmenu;

var XG_OK = 1;
var XG_FAIL = 0;
var XG_ERROR = -1;
var XG_IOERR = -2;
var XG_SYSERR = -3;
var XG_NETERR = -4;
var XG_TIMEOUT = -5;
var XG_DATAERR = -6;
var XG_SYSBUSY = -7;
var XG_PARAMERR = -8;
var XG_NOTFOUND = -9;
var XG_NETCLOSE = -10;
var XG_NETDELAY = -11;
var XG_SENDFAIL = -12;
var XG_RECVFAIL = -13;
var XG_AUTHFAIL = -14;
var XG_DAYLIMIT = -15;
var XG_DUPLICATE = -16;
var XG_UNINSTALL = -17;
var XG_DETCHCONN = -999999;

var getSequence = ((
	function(){
	var id = 0; 
	return function(){
		return ++id;
	};
})());

$.extend({
	pack: function(elem){
		if (isObject(elem)){
			if (isFunction(elem.attr)) return elem;
		}
		else{
			elem = getString(elem);
			var ch = elem.charAt(0);
			if (ch == '_') return $('#' + elem);
			if (ch >= 'a' && ch <= 'z') return $('#' + elem);
			if (ch >= 'A' && ch <= 'Z') return $('#' + elem);
			if (ch >= '0' && ch <= '9') return $('#' + elem);
		}

		return $(elem);
	}
});

Array.prototype.pop_front = function(count){
	if (typeof(count) === 'undefined') this.splice(0, 1);
	if (typeof(count) === 'number') this.splice(0, count);
}

Array.prototype.push_front = function(){
	for (var i = 0; i < arguments.length; i++) this.splice(i, 0, arguments[i]);
}

String.prototype.colorHex = function(){
	var res = '#';
	var that = this;
	if(/^(rgb|RGB)/.test(that)){
		var color = that.replace(/(?:\(|\)|rgb|RGB)*/g, '').split(',');
		for (var i = 0; i < color.length; i++){
			var hex = Number(color[i]).toString(16);
			if (hex === '0') hex += hex;	
			res += hex;
		}
		return res.length == 7 ? res : that;
	}
	else{
		var num = that.replace(/#/, '').split('');
		if (num.length === 6) return that;	
		if (num.length === 3){
			for (var i = 0; i < num.length; i += 1) res += num[i] + num[i];
			return res;
		}
	}
	return that;
};

String.prototype.replaceAll = function(src, dest){
    return this.replace(new RegExp(src, 'gm'), dest);
}

var IconPicker = function(elem, path){
	 this.datalist = getIconList(path);
	 this.initialize(getCtrl(elem));
}

IconPicker.prototype = {
	initialize: function(elem){
		var count = 0;
		var self = this;
		var pack = $('#IconPickerTable');
		var html = "<table class='IconPickerTable' id='IconPickerTable'>";

		if (pack && strlen(pack.html()) > 64 && navigator.userAgent.indexOf('Firefox') >= 0){
			this.div = pack.parent()[0];
		}
		else{
			var cols = (this.datalist.length > 20) ? 8 : 6;
			var rows = Math.ceil(this.datalist.length / cols);

			for (i = 0; i < rows; i++){
				html += "<tr>";

				for (j = 0; j < cols && count < this.datalist.length; j++){
					html += '<td style="background-image:url(' + this.datalist[count] + ')"></td>';
					count++;
				}
			   
				html+= "</tr>";
			}
			
			html += '</table>';

			this.div = document.createElement('div');
			this.div.innerHTML = html;
		}

		this.trigger = elem;
		
		var sz = this.trigger.clientWidth;
		var tds = this.div.getElementsByTagName('td');

		for (var i = 0, l = tds.length ; i < l; i++){
			tds[i].onmousedown = function(e){
				self.setIcon(self.trigger, this.style.backgroundImage);
				self.trigger.blur();
				e.stopPropagation();
			}

			if (tds[i].style.backgroundImage == self.trigger.style.backgroundImage){
				tds[i].style.backgroundColor = 'red';
			}
			else{
				tds[i].style.backgroundColor = '#EEE';
			}
			
			tds[i].style.margin = '0px';
			tds[i].style.padding = '0px';
			tds[i].style.width = sz + 'px';
			tds[i].style.height = sz + 'px';
		}

		this.trigger.parentNode.appendChild(this.div);
		this.div.style.zIndex = 1000;
		this.div.style.position = 'fixed';
		this.div.style.left = getLeft(this.trigger) + 'px'
		this.div.style.top = (this.trigger.clientHeight + getTop(this.trigger) + 1) + 'px';
		this.trigger.onclick = function(){
			if(self.div.style.display == 'none'){
				self.show();
			}
			else{
				self.hide();
		   }
		}
	},
	
	setIcon : function(trigger, color){
		trigger.style.backgroundImage = color;
		if (strlen(trigger.value) > 0){
			trigger.value = color.colorHex().toUpperCase();
		}
		this.hide();
	},
	
	hide : function(){
		this.div.style.display = 'none'
	},
	
	show : function(){
		this.div.style.display = 'block'
	}
}

var ColorPicker = function(elem){
	 this.datalist = [
			'#000000','#993300','#333300','#003300','#003366','#000080','#333399','#333333',
			'#800000','#FF6600','#808000','#008000','#008080','#0000FF','#666699','#808080',
			'#FF0000','#FF9900','#99CC00','#339966','#33CCCC','#3366FF','#800080','#999999',
			'#FF00FF','#FFCC00','#FFFF00','#00FF00','#00FFFF','#00CCFF','#993366','#CCCCCC',
			'#FF99CC','#FFCC99','#FFFF99','#CCFFCC','#CCFFFF','#99CCFF','#CC99FF','#FFFFFF'];
	 this.initialize(getCtrl(elem));
}

ColorPicker.prototype = {
	initialize: function(elem){
		var count = 0;
		var self = this;
		var pack = $('#ColorPickerTable');
		var html = "<table class='ColorPickerTable' id='ColorPickerTable'>";

		if (pack && strlen(pack.html()) > 64 && navigator.userAgent.indexOf('Firefox') >= 0){
			this.div = pack.parent()[0];
		}
		else{
			var cols = 8;
			var rows = Math.ceil(this.datalist.length / cols);

			for (i = 0; i < rows; i++){
				html += "<tr>";

				for (j = 0; j < cols && count < this.datalist.length; j++){
					html += '<td style="text-shadow:0px 1px 1px #CCBBAA;background:' + this.datalist[count]+ '"></td>';
					count++;
				}
			   
				html+= "</tr>";
			}

			html += '</table>';

			this.div = document.createElement('div');
			this.div.innerHTML = html;
		}
		
		this.trigger = elem;
		
		var tds = this.div.getElementsByTagName('td');

		for (var i = 0, l = tds.length ; i < l; i++){
			tds[i].onmousedown = function(e){
				self.setColor(self.trigger, this.style.backgroundColor);
				self.trigger.blur();
				e.stopPropagation();
			}

			if (tds[i].style.backgroundColor == self.trigger.style.backgroundColor){
				tds[i].innerHTML = '&#10004';
			}
			else{
				tds[i].innerHTML = '';
			}

			tds[i].style.margin = '0px';
			tds[i].style.padding = '0px';
		}
		this.trigger.parentNode.appendChild(this.div);
		this.div.style.zIndex = 1000;
		this.div.style.position = 'fixed';
		this.div.style.left = getLeft(this.trigger) + 'px'
		this.div.style.top = (this.trigger.clientHeight + getTop(this.trigger) + 1) + 'px';
		this.trigger.onclick = function(){
			if(self.div.style.display == 'none'){
				self.show();
			}
			else{
				self.hide();
		   }
		}
	},
	
	setColor : function(trigger, color){
		trigger.style.backgroundColor = color;
		if (strlen(trigger.value) > 0){
			trigger.value = color.colorHex().toUpperCase();
		}
		this.hide();
	},
	
	hide : function(){
		this.div.style.display = 'none'
	},
	
	show : function(){
		this.div.style.display = 'block'
	}
}

var AutoTextPicker = function(elem, words){
	 this.datalist = words;
	 this.initialize(getCtrl(elem));
}

AutoTextPicker.prototype = {
	count: 0,
	index: -1,
	onclick: null,
	onselect: null,
	selected: null,
	initialize: function(elem){
		var cols = 1;
		var self = this;
		var rows = Math.ceil(this.datalist.length / cols);
		var html = "<table id='AutoTextPickerTable' width='100%'>";

		for (i = 0; i < rows; i++){
			html += "<tr class='AutoDataRow'>";

			for (j = 0; j < cols && self.count < this.datalist.length; j++){
				html += '<td>'+ this.datalist[self.count] + '</td>';
				self.count++;
			}
		   
			html+= "</tr>";
		}

		html += '</table>';

		this.div = document.createElement('div');
		this.div.innerHTML = html;
		
		this.trigger = elem;
		this.trigger.parentNode.appendChild(this.div);
		
		this.updateStatus(self);
		
		this.div.style.zIndex = 1000;
		this.div.style.overflow = 'auto';
		this.div.style.position = 'fixed';
		this.div.style.border = '1px solid #ABC';
		this.div.style.left = getLeft(this.trigger) + 'px';
		this.div.style.width = this.trigger.clientWidth + 'px';
		this.div.style.top = (this.trigger.clientHeight + getTop(this.trigger) + 2) + 'px';
		
		this.trigger.onclick = function(){
			if(self.div.style.display == 'none'){
				self.show();
			}
			else{
				self.hide();
		   }
		};
		
		this.trigger.onkeydown = function(e){
			if (e.keyCode == 13){
				self.hide();
			}
			else if (e.keyCode == 38){
				self.selectItem(self, -1);
				e.preventDefault();
			}
			else if (e.keyCode == 40){
				self.selectItem(self, 1);
				e.preventDefault();
			}
		};
	},
	
	selectItem : function(self, step){
		self.index += step;
		
		if (self.index < 0) self.index = self.count - 1;
		if (self.index >= self.count) self.index = 0;

		var tds = self.div.getElementsByTagName('td');

		for (var i = 0, l = tds.length ; i < l; i++){
			if (self.index == i){
				self.setText(self.trigger, tds[i].innerHTML);
				break;
			}
		}

		self.show();
	},
	
	destroy : function(){
		$(this.div).remove();
	},
	
	updateStatus : function(self){
		var tds = self.div.getElementsByTagName('td');

		for (var i = 0, l = tds.length ; i < l; i++){
			$(tds[i]).attr('index', i);

			tds[i].onmousedown = function(){
				self.setText(self.trigger, this.innerHTML);
				self.index = parseInt($(this).attr('index'));
				self.trigger.blur();
				
				if (self.onclick) self.onclick(this.innerHTML);
			}
			
			if (self.selected){
				if (self.selected(tds[i].innerHTML, self.trigger.value)){
					tds[i].style.background = '#BCD';
					tds[i].style.color = '#800';
					self.index = i;
				}
				else{
					tds[i].style.background = '#FFF';
					tds[i].style.color = '#234';
				}
			}
			else{
				if (tds[i].innerHTML == self.trigger.value){
					tds[i].style.background = '#BCD';
					tds[i].style.color = '#800';
					self.index = i;
				}
				else{
					tds[i].style.background = '#FFF';
					tds[i].style.color = '#234';
				}
			}
		}
		
		$('#AutoTextPickerTable td').css('margin', '0px');
		$('#AutoTextPickerTable td').css('cursor', 'default');
		$('#AutoTextPickerTable td').css('padding', $(self.trigger).css('padding'));
		$('#AutoTextPickerTable td').css('font-size', $(self.trigger).css('font-size'));
	},
	
	setText : function(trigger, text){
		this.hide();
		trigger.value = text;
		if (onselect) onselect(text);
	},
	
	hide : function(){
		this.div.style.display = 'none';
	},
	
	show : function(){
		this.div.style.display = 'block';
		this.updateStatus(this);
	}
}

function getSpace(){
	return '';
}

function getLanguage(){
	return lang;
}

function clearCookie(){
	var keys = document.cookie.match(/[^ =;]+(?=\=)/g);
	if (keys){
		var i = keys.length;
		while (i--){
			document.cookie = keys[i]+'=0;expires=' + new Date(0).toUTCString();
		}
		setCurrentUser(null);
	}
}

function getClientWidth(){
	return document.documentElement.clientWidth || document.body.clientWidth;
}

function getClientHeight(){
	return document.documentElement.clientHeight || document.body.clientHeight;
}

function clearStorage(){
	localStorage.clear();
}

function getStorage(key){
	return localStorage.getItem(key);
}

function removeStorage(key){
	localStorage.removeItem(key);
}

function setStorage(key, val){
	localStorage.setItem(key, val);
}

function clearSession(){
	sessionStorage.clear();
}

function getSession(key){
	return sessionStorage.getItem(key);
}

function removeSession(key){
	sessionStorage.removeItem(key);
}

function setSession(key, val){
	sessionStorage.setItem(key, val);
}

function removeResizeCallback(name){
	delete autoresizemap[name];
}

function setResizeCallback(name, func){
	autoresizemap[name] = func;
}

function clearSingletonInterval(name){
	if (name == null){
		for (var name in singletontimermap) clearInterval(singletontimermap[name]);
		singletontimermap = {};
	}
	else{
		if (name in singletontimermap){
			clearInterval(singletontimermap[name]);
			delete singletontimermap[name];
		}
	}
}

function setSingletonInterval(name, delay, func){
	if (name in singletontimermap) clearInterval(singletontimermap[name]);
	singletontimermap[name] = setInterval(func, delay);
}

function getParameter(name){
   var reg = new RegExp('(^|&)'+ name +'=([^&]*)(&|$)');
   var res = window.location.search.substr(1).match(reg);
   return res ? unescape(res[2]) : null;
}

function getFileName(path){
	var pos = path.lastIndexOf('/');
	return pos >= 0 ? path.substring(pos + 1) : path;
}

function getFileExtname(path){
	var pos = path.lastIndexOf('.');
	return pos >= 0 ? path.substring(pos + 1).toLowerCase() : '';
}

function isFileName(name, required, maxlen){
	var len = strlen(name);

	if (len == 0) return required ? false : true;

	if (maxlen == null) maxlen = 64;

	var errstr = "`'^*<>,:;?|%\r\n\t\"\\/";

	if (len > maxlen) return false;

	for (var i = 0; i < len; i++){
		if (errstr.indexOf(name[i]) >= 0) return false;
	}

	return true;
}

function isFilePath(name, required, maxlen){
	var len = strlen(name);

	if (len == 0) return required ? false : true;

	if (maxlen == null) maxlen = 64;

	var errstr = "`'^*<>,:;?|%\r\n\t\"";

	if (len > maxlen) return false;

	for (var i = 0; i < len; i++){
		if (errstr.indexOf(name[i]) >= 0) return false;
	}

	return true;
}

function getDateTimeString(date){
	if (date == null) date = new Date();

	return date.getFullYear() + '-' + getString(100 + date.getMonth() + 1).substr(1)
			+ '-' + getString(100 + date.getDate()).substr(1)
			+ ' ' + getString(100 + date.getHours()).substr(1)
			+ ':' + getString(100 + date.getMinutes()).substr(1)
			+ ':' + getString(100 + date.getSeconds()).substr(1);
}

function getShortDateTimeString(date){
	if (date == null) date = new Date();

	return date.getFullYear() + getString(100 + date.getMonth() + 1).substr(1)
			+ getString(100 + date.getDate()).substr(1)
			+ getString(100 + date.getHours()).substr(1)
			+ getString(100 + date.getMinutes()).substr(1)
			+ getString(100 + date.getSeconds()).substr(1);
}

function dispatch(elem, name){
	var event = document.createEvent('Event');
	event.initEvent(name, true, true);
	getCtrl(elem).dispatchEvent(event);
}

function strlen(str){
	if (str == null) return 0;

	var ch;
	var len = 0;
	var val = str + '';
	
	for (var i = 0; i < val.length; i++){
		ch = val.charCodeAt(i);
		if ((ch >= 0x0001 && ch <= 0x007E) || (0xFF60 <= ch && ch <= 0xFF9F)){
			len++;
		}
		else{
			len += 2;
		}
	}
	
	return len;
}

function markdown(msg){
	var str = 0;
	var end = 0;
	var res = '';
	var src = msg;
	var tmp = null;
	var updated = false;
	var linetag = 'falryepqnfapfywrwd';
	
	while (true){
		str = msg.indexOf('```');
		if (str < 0){
			res += msg;
			break;
		}

		str += 3
		res += msg.substr(0, str);

		end = msg.indexOf('```', str);
		if (end < 0){
			res += msg.substr(str);
			updated = false;
			break;
		}

		tmp = msg.substring(str, end += 3).replace(new RegExp('\n\t', 'gm'), '\n\t\t');
		tmp = tmp.replace(new RegExp('\n--', 'gm'), '\n#' + linetag);
		tmp = tmp.replace(new RegExp('\n', 'gm'), linetag + '\n');
		msg = msg.substr(end);
		updated = true;
		res += tmp;
	}

	if (updated){
		msg = marked(res).replace(new RegExp('#' + linetag, 'gm'), '--');
		msg = msg.replace(new RegExp(linetag, 'gm'), '');
	}
	else{
		msg = marked(src);
	}

	return "<div class='MarkdownContentDiv'>" + msg + "</div>";
}

function isObject(val){
	return typeof(val) == 'object';
}

function isString(val){
	return typeof(val) == 'string';
}

function isFunction(val){
	return typeof(val) == 'function';
}

function getString(val){
	if (strlen(val) == 0) return '';
	return '' + val;
}

function centerText(text, weight){
	if (weight) return "<div style='text-align:center;font-weight:" + weight + "'>" + text + "</div>";
	else return "<div style='text-align:center'>" + text + "</div>";
}

function loadStyle(url){
	var elem = document.createElement('link');
	elem.href = url;
	elem.type = 'text/css';
	elem.rel = 'stylesheet';
	document.getElementsByTagName('head')[0].appendChild(elem);
	return elem;
}

function loadScript(url){
	var elem = document.createElement('script');
	elem.type = 'text/javascript';
	elem.src = url;
	document.getElementsByTagName('head')[0].appendChild(elem);
	return elem;
}

function checkEmail(mail){
　　var reg = /^[a-zA-Z0-9_-]+@([a-zA-Z0-9]+\.)+(com|cn|net|org)$/;
　　return reg.test(mail);
}

function getTextSize(text){
	var sz = strlen(text);

	if (machinetype == 'PC'){
		return sz > 0 ? sz : 1;
	}
	else{
		return sz > 0 ? sz : 1;
	}
}

function setLanguage(language){
	if (strlen(language) > 0){
		lang = (language == 'CN' ? 'CN' : 'EN');
	}
}

function setLabelText(elem, text){
	$.pack(elem).attr('size', getTextSize(text)).val(text);
}

function getBrowserInfo(){
	if (browserinfo) return browserinfo;

	var ua = navigator.userAgent.toLowerCase();
	var msie = (ua.match(/firefox|chrome|safari|opera/g) || 'other')[0];
	
	if ((ua.match(/msie|trident/g) || [])[0]) msie = 'msie';

	var pc;
	var plat;
	var prefix;

	if ('ontouchstart' in window || ua.indexOf('touch') !== -1 || ua.indexOf('mobile') !== -1){
		if (ua.indexOf('ipad') !== -1){
			pc = 'pad';
		}
		else if ( ua.indexOf('mobile') !== -1){
			pc = 'mobile';
		}
		else if (ua.indexOf('android') !== -1){
			pc = 'android';
		}
		else{
			pc = 'pc';
		}
	}
	else{
		pc = 'pc';
	}
	
	machinetype = pc.toUpperCase();

	switch (msie){
		case 'chrome':
		case 'safari':
		case "mobile":
			prefix = 'webkit';
			break;
		case 'msie':
			prefix = 'ms';
			break;
		case 'firefox':
			prefix = 'moz';
			break;
		case 'opera':
			prefix = 'opera';
			break;
		default:
			prefix = 'webkit';
			break
	}

	plat = (ua.indexOf('android') > 0) ? 'android' : navigator.platform.toLowerCase();
	
	browserinfo = {
		version: (ua.match(/[\s\S]+(?:rv|it|ra|ie)[\/: ]([\d.]+)/) || [])[1],
		pc: pc,
		plat: plat,
		type: msie,
		prefix: prefix
	};
	
	return browserinfo;
}

function getContextMenuView(){
	return contextmenuattach;
}

function getContextMenuAttach(){
	return contextmenuattach;
}

function bindContextMenu(elem, menu){
	elem = getCtrl(elem);
	menu = getCtrl(menu);

	menu.onclick = function(){
		document.oncontextmenu = defaultcontextmenu;
		menu.style.display = 'none';
	}

	menu.onclick();

	elem.onmouseup = function(e){
		if (window.event) e = window.event;

		e.stopPropagation();

		if (e.button == 2){
			document.oncontextmenu = function(e){
				if(window.event){
					e = window.event;
					e.returnValue = false;
				}
				else{
					e.preventDefault();
				}
			}

			var x = e.clientX - 1;
			var y = e.clientY - 1;

			menu.style.cssText = 'z-index:10000;position:fixed;display:block;left:' + x + 'px;' + 'top:' + y + 'px;';
			contextmenuattach = elem;
			contextmenuview = menu;
		}
	}
}

function getDateTime(diff, seperator){
	var now = new Date();
	
	if (diff) now.setDate(now.getDate() + diff);

	var len = strlen(seperator);
	var D = now.getDate();
	var M = now.getMonth();
	var h = now.getHours();
	var m = now.getMinutes();
	var s = now.getSeconds();

	if (len == 0){
		seperator = '- :';
	}
	else if (len == 1){
		seperator = seperator + ' :';
	}
	else if (len == 2){
		seperator = seperator + ':';
	}
	
	M = M + 1;

	if (D < 10) D = '0' + D;
	if (M < 10) M = '0' + M;
	if (h < 10) h = '0' + h;
	if (m < 10) m = '0' + m;
	if (s < 10) s = '0' + s;
	
	return now.getFullYear() + seperator.charAt(0) + M + seperator.charAt(0) + D + seperator.charAt(1) + h + seperator.charAt(2) + m + seperator.charAt(2) + s;
}

function getAmountString(val){
	if (strlen(val) == 0) return '0.00';
	if (getString(val).indexOf('.') < 0) return val + '.00';
	if ((val = parseFloat(getString(val))) == null) return '0.00';

	val = getString(val);
	
	var pos = val.indexOf('.');
	
	if (pos > 0){
		var len = strlen(val.substring(pos + 1));

		if (len == 2) return val;
		else if (len == 1) return val + '0';
		else if (len == 0) return val + '00';
		else return val.substring(0, pos + 3);
	}

	return val + '.00';
}

function getCtrl(elem){
	return $.pack(elem)[0];
}

function appendCtrl(elem){
	var ctrl = getCtrl(elem);
	if (getCtrl(ctrl.id) == null) document.body.appendChild(ctrl);
	return getCtrl(ctrl.id);
}

function createCtrl(tag, id){
	if (id == null) return document.createElement(tag);
	var ctrl = getCtrl(id);
	if (ctrl == null){
		ctrl = document.createElement(tag);
		ctrl.id = id;
	}
	return ctrl;
}

function getTop(elem){
	var rect = getCtrl(elem).getBoundingClientRect(); 
	return rect.top - document.documentElement.clientTop; 
}

function getLeft(elem){
	var rect = getCtrl(elem).getBoundingClientRect(); 
	return rect.left - document.documentElement.clientLeft; 
}

function getWidth(elem){
	return $.pack(elem).width();
}

function getHeight(elem){
	return $.pack(elem).height();
}

function setWidth(elem, width){
	return $.pack(elem).width(width);
}

function setHeight(elem, height){
	return $.pack(elem).height(height);
}

function isJsonString(str){
	try{
		JSON.parse(str);
		return true;
	}
	catch(e){
		return false;
	}
}

function getIconList(path){
	var iconlist = [];

	getHttpResult('/GetIconList', {path: getString(path)}, function(data){
		if (data.code > 0) iconlist = data.list;
	});

	return iconlist;
}

function graspCanvas(elem, scale, func){
	elem = getCtrl(elem);

	if (scale == null) scale = 1;

	var canvas = document.createElement('canvas');
	var width = elem.offsetWidth;
	var height = elem.offsetHeight;
	var context = canvas.getContext('2d');

	canvas.width = width * scale;
	canvas.height = height * scale;
	context.scale(scale, scale);

	var opts = {
		dpi: window.devicePixelRatio * scale,
		scale: 1,
		canvas: canvas,
		useCORS: true
	};

	html2canvas(elem, opts).then(func);
}

function getCursorLocation(){
	if (mousemovevent == null){
		document.onmousemove = function(ev){
			mousemovevent = (ev || window.event);
		};
	
		return null;
	}

	var ev = mousemovevent;
	
	if (ev.pageX || ev.pageY){
		return {x: ev.pageX, y: ev.pageY};
	}
	
	return {
		x: ev.clientX + document.body.scrollLeft - document.body.clientLeft,
		y: ev.clientY + document.body.scrollTop - document.body.clientTop
	};
}

function getBackgroundImage(elem){
	var icon = $.pack(elem).css('background-image');

	if (icon.indexOf('/res') >= 0){
		icon = icon.substring(icon.indexOf('/res'));
	}
	else if (icon.indexOf('/app') >= 0){
		icon = icon.substring(icon.indexOf('/app'));
	}
	else if (icon.indexOf('\'') >= 0){
		icon = icon.substring(icon.indexOf('\'') + 1);
	}
	else if (icon.indexOf('\"') >= 0){
		icon = icon.substring(icon.indexOf('\"') + 1);
	}
	
	icon = icon.substring(0, icon.lastIndexOf(')')) || icon;
	icon = icon.substring(0, icon.lastIndexOf('\'')) || icon;
	icon = icon.substring(0, icon.lastIndexOf('\"')) || icon;
	
	return icon;
}

function getVue(elem, data, method, filter){
	return new Vue({el: '#' + getCtrl(elem).id, data: data, methods: method, filters: filter});
}

function getHttpResult(url, data, func, async, json){
	var result = {code: XG_NETERR};
	var contype = 'application/x-www-form-urlencoded';

	if (json){
		contype = 'application/json';
		data = JSON.stringify(data);
	}

	$.ajax({
		url: url,
		data: data,
		cache: false,
		contentType: contype,
		type: data ? 'POST' : 'GET',
		async: async ? true : false,
		success: function(msg){
			try{
				result = JSON.parse(msg);
			}
			catch(e){
				result = msg;
			}

			if (func) func(result, msg);
		},
		error: function(data){
			data['code'] = XG_ERROR;
			if (func) func(data);
			result = data;
		}
	});

	return async ? true : result;
}


function getHttpCacheKey(url, data){
	var user = getCurrentUser() || '{logout}';
	if (data == null) return 'cachekey[' + user + '][' + url + ']';
	data = Object.keys(data).map(key => key + '=' + data[key]).join('&');
	return 'cachekey[' + user + '][' + url + '][' + data + ']';
}

function removeHttpCache(url, data){
	removeStorage(getHttpCacheKey(url, data));
}

function getHttpCacheResult(url, data, func, async, json){
	var val = {};
	var now = getDateTimeString();
	var key = getHttpCacheKey(url, data);

	try{
		val = JSON.parse(getStorage(key));

		if (data == null) data = {};

		if (val.cachetime.startsWith(now.substring(0, 10))){
			if (val.version && !data.version) data.version = val.version;
			if (val.statetime && !data.statetime) data.statetime = val.statetime;
		}
	}
	catch(e){
		val = {};
	}

	return getHttpResult(url, data, function(data, msg){
		if ((val.version && val.version == data.version) || (val.statetime && val.statetime == data.statetime)){
			if (func) func(val);
		}
		else{
			if (func) func(data);

			if (data.version || data.statetime){
				removeStorage(key);
				data.cachetime = now;
				setStorage(key, JSON.stringify(data))
			}
		}
	}, async, json);
}

function MoveFunc(elem){
	elem = getCtrl(elem);

	var result = {x : elem.offsetLeft, y : elem.offsetTop};

	elem = elem.offsetParent;
	
	while (elem){
		result.x += elem.offsetLeft;
		result.y += elem.offsetTop;
		elem = elem.offsetParent;
	}
	
	return result;	  
};

function Endrag(source, target){
	var x0 = 0, y0 = 0, x1 = 0, y1 = 0;
	var moveable = false, NS = navigator.appName == 'Netscape';
	
	source = getCtrl(source);
	target = getCtrl(target);
   
	source.style.cursor = 'move';
	
	source.onmousedown = function(e){
		e = e || window.event;

		if (e.button == NS ? 0 : 1){
			if (!NS) this.setCapture();
			x0 = e.clientX ; 
			y0 = e.clientY ; 
			x1 = parseInt(MoveFunc(target).x); 
			y1 = parseInt(MoveFunc(target).y);   
			moveable = true;
		} 
	};
	
	source.onmousemove = function(e){
		e = e || window.event;
		
		if (moveable){
			target.style.top = (y1 + e.clientY - y0) + 'px';
			target.style.left = (x1 + e.clientX - x0) + 'px';
		} 
	};

	source.onmouseup = function(e){
		if (moveable){
			if (!NS) this.releaseCapture();
			moveable = false; 
		} 
	};
}

function hideMsgBox(){
	$('#XG_MSGBOX_DIV_ID').hide();
	$('#XG_MODESCREEN_DIV_ID').fadeOut();
}

function hideToastBox(force){
	if (force){
		$('#XG_TOAST_DIV_ID').remove();
		$('#XG_TOAST_MODESCREEN_DIV_ID').remove();
	}
	else{
		$('#XG_TOAST_DIV_ID').hide();
		$('#XG_TOAST_MODESCREEN_DIV_ID').fadeOut();
	}

	if (statuslabel) $(statuslabel).html('');
}

function showMsgBox(mode){
	$('#XG_MSGBOX_DIV_ID').show();
	if (mode == null || mode){
		$('#XG_MODESCREEN_DIV_ID').fadeIn();
	}
}

function getScrollTop(){ 
    var top = 0;
	
    if(document.documentElement && document.documentElement.scrollTop){
        top = document.documentElement.scrollTop;
    }
	else if(document.body){
        top = document.body.scrollTop;
    }

    return top;   
}

function setStatusLabel(elem){
	statuslabel = getCtrl(elem);
}

function centerWindow(elem, ox, oy){
	var wnd = getCtrl(elem);
	var x = (getClientWidth() - wnd.offsetWidth) / 2;
	var y = (getClientHeight() - wnd.offsetHeight) / 2;
	if (ox) x += ox;
	if (oy) y += oy;
	if (y < 8) y = 8;
	if (y > 200) y -= y / 8;

	wnd.style.left = x + 'px';
	wnd.style.top = getScrollTop() + y + 'px';
}

function setToastTitle(title){
	$('#XG_TOAST_TITLE_LABEL_ID').html(title);
}

function setToastErrorText(msg){
	setToastTitle("<font color='#D00'>" + msg + "</font>");
}

function setMessageTitle(title){
	$('#XG_MSGBOX_TITLE_LABEL').html('&nbsp' + title);
}

function setMessageErrorText(text, elem){
	$('#XG_MSGBOX_ERRMSG_LABEL').html(text);

	if (elem && strlen(text) > 0){
		$.pack(elem).focus().bind('input propertychange',function(){
			$('#XG_MSGBOX_ERRMSG_LABEL').html('');
		});
	}
}

function showToastMessage(msg, mode, timeout, width, closefunc){
	hideToastBox(true);

	var MsgBoxDiv = createCtrl('div', 'XG_TOAST_DIV_ID');
	
	appendCtrl(MsgBoxDiv);

	if (mode == null || mode){
		var ModeScreenDiv = createCtrl('div', 'XG_TOAST_MODESCREEN_DIV_ID');
		
		appendCtrl(ModeScreenDiv);

		if (machinetype == 'MOBILE'){
			ModeScreenDiv.style.background = 'none';
		}

		ModeScreenDiv.style.display = 'none';
		ModeScreenDiv.style.top = getScrollTop() + 'px';

		$('#XG_TOAST_MODESCREEN_DIV_ID').fadeIn();
	}

	if (strlen(width) == 0) width = 'auto';

	msg = "<div id='XG_TOAST_CONTENT_DIV_ID'>" + msg + "</div>";

	if (closefunc){
		$(MsgBoxDiv).html("<span id='XG_TOAST_TITLE_LABEL_ID'></span><span id='XG_TOAST_CLOSE_BUTTON_ID'></span></br>" + msg);

		$('#XG_TOAST_CLOSE_BUTTON_ID').click(function(){
			if (isFunction(closefunc)){
				var flag = closefunc();
				if (flag == null || flag) hideToastBox();
			}
			else{
				hideToastBox();
			}
		});
	}
	else{
		$(MsgBoxDiv).html(msg);
	}

	MsgBoxDiv.style.width = width;
	MsgBoxDiv.style.display = 'inline-block';
   	MsgBoxDiv.setAttribute('unselectable', 'on');
	MsgBoxDiv.setAttribute('onselectstart', 'return false');

   	centerWindow(MsgBoxDiv, 0, 0);

	if (toasthidetimer){
		clearTimeout(toasthidetimer);
		toasthidetimer = null;
	}

	if (timeout && timeout > 0){
		toasthidetimer = setTimeout(hideToastBox, timeout);
	}

	var msgbox = {};

	msgbox['dialog'] = MsgBoxDiv;
	msgbox['timeout'] = timeout;

	msgbox['title'] = function(msg){
		$('#XG_TOAST_TITLE_LABEL_ID').html(msg);
	};

	msgbox['center'] = function(){
		centerWindow(MsgBoxDiv, 0, 0);
	}

	return msgbox;
}

function showToast(msg, timeout, width){
	if (timeout == null){
		var len = strlen(msg);
		
		if (len < 10) timeout = 1500;
		else if (len < 20) timeout = 2000;
		else if (len < 30) timeout = 2500;
		else timeout = 3000;
	}

	if (statuslabel) $(statuslabel).css('color', '#68A').html(msg);

	return showToastMessage(msg, false, timeout, width);
}

function showErrorToast(msg, timeout, width){
	if (timeout == null){
		var len = strlen(msg);
		
		if (len < 10) timeout = 2000;
		else if (len < 20) timeout = 2500;
		else if (len < 30) timeout = 3000;
		else timeout = 3500;
	}
	
	if (statuslabel) $(statuslabel).css('color', '#823').html(msg);

	return showToastMessage(msg, true, timeout, width);
}
function addMsgBoxOption(html){
	return $('#XG_MSGBOX_DIV_CONFIRM_ID').parent().append(html).children().last();
}
function showMessage(msg, title, width, mode, func, attach, data){
	hideMsgBox();
	hideToastBox();

	var MsgBoxDiv = createCtrl('div', 'XG_MSGBOX_DIV_ID');
	
	appendCtrl(MsgBoxDiv);

	if (mode == null || mode){
		var ModeScreenDiv = createCtrl('div', 'XG_MODESCREEN_DIV_ID');
		
		appendCtrl(ModeScreenDiv);

		ModeScreenDiv.style.display = 'none';
		ModeScreenDiv.style.top = getScrollTop() + 'px';

		$('#XG_MODESCREEN_DIV_ID').fadeIn();
	}
	
	if (strlen(width) == 0) width = 'auto';

	MsgBoxDiv.style.display = 'inline-block';

	var str = "<table><tr><td id='XG_MSGBOX_DIV_TITLE_ID'></td></tr><tr><td><div id='XG_MSGBOX_TEXT_ID'></div></td></tr><tr id='XG_MSGBOX_OPTION_ROW_ID'><td><div style='margin-top:2px;padding-top:6px;text-align:center;border-top:1px solid #888'><button class='TextButton' id = 'XG_MSGBOX_DIV_CONFIRM_ID' onclick='hideMsgBox()'></button>";
	
	if (strlen(attach) > 0) str += attach;

	str += "</div></td></tr></table>";
	
	$(MsgBoxDiv).html(str);

	var MsgLabel = getCtrl('XG_MSGBOX_TEXT_ID');
	var MsgTitle = getCtrl('XG_MSGBOX_DIV_TITLE_ID');
	var ConfirmBtn = getCtrl('XG_MSGBOX_DIV_CONFIRM_ID');

	MsgLabel.style.width = width;

	new Endrag('XG_MSGBOX_DIV_TITLE_ID', 'XG_MSGBOX_DIV_ID');
	
	if (getLanguage() == 'CN'){
		if (title == null) title = '信息';
		ConfirmBtn.innerText = '确认';
	}
	else{
		if (title == null) title = 'MESSAGE';
		ConfirmBtn.innerText = 'CONFIRM';
	}

	$(MsgLabel).html(msg);
	$(MsgTitle).html("<label id='XG_MSGBOX_TITLE_LABEL'>" + title + "</label><label id='XG_MSGBOX_ERRMSG_LABEL'/><label class='ImageButton' id='XG_MSGBOX_CLOSE_ICON'></label>");
	
	var CloseIcon = getCtrl('XG_MSGBOX_CLOSE_ICON');
	var TitleLabel = getCtrl('XG_MSGBOX_TITLE_LABEL');
	
	CloseIcon.onclick = function(){
		if (func == null){
			hideMsgBox();
		}
		else{
			var res = func(0);
			
			if (res == null || res){
				hideMsgBox();
			}
		}
	}

	ConfirmBtn.onclick = function(){
		if (func == null){
			hideMsgBox();
		}
		else{
			var res = func(1);
			
			if (res == null || res){
				hideMsgBox();
			}
		}
	}
	
	getVue('XG_MSGBOX_TEXT_ID', data);
	
	MsgBoxDiv.setAttribute('unselectable', 'on');
	MsgBoxDiv.setAttribute('onselectstart', 'return false');
   	
   	centerWindow(MsgBoxDiv, 0, 0);
	
	var msgbox = {};
	
	msgbox['dialog'] = MsgBoxDiv;
	msgbox['confirm'] = ConfirmBtn.onclick;
	
	msgbox['title'] = function(msg){
		$('#XG_MSGBOX_TITLE_LABEL').html(msg);
	};
	
	msgbox['text'] = function(msg){
		$('#XG_MSGBOX_TEXT_ID').html(msg);

		centerWindow(MsgBoxDiv, 0, 0);
	};
	
	msgbox['hideOption'] = function(){
		$('#XG_MSGBOX_OPTION_ROW_ID').hide();
	};
	
	msgbox['showOption'] = function(){
		$('#XG_MSGBOX_OPTION_ROW_ID').show();
	};

	msgbox['setErrorText'] = function(text, elem){
		setMessageErrorText(text, elem);
	};

	msgbox['center'] = function(){
		centerWindow(MsgBoxDiv, 0, 0);
	}

	return msgbox;
}

function showConfirmMessage(msg, title, func, width, mode, data){
	var msgbox = null;
	
	if (getLanguage() == 'CN'){
		msgbox = new showMessage(msg, title, width, mode, func, "<label>&nbsp;&nbsp;</label><button class='TextButton' id='XG_MSGBOX_DIV_CANCEL_ID' onclick='hideMsgBox()'>取消</button>", data);
	}
	else{
		msgbox = new showMessage(msg, title, width, mode, func, "<label>&nbsp;&nbsp;</label><button class='TextButton' id='XG_MSGBOX_DIV_CANCEL_ID' onclick='hideMsgBox()'>CANCEL</button>", data);
	}

	var CancelBtn = getCtrl('XG_MSGBOX_DIV_CANCEL_ID');
	
	CancelBtn.onclick = function(){
		if (func == null){
			hideMsgBox();
		}
		else{
			var res = func(0);
			
			if (res == null || res) hideMsgBox();
		}
	}
	
	msgbox['cancel'] = CancelBtn.onclick;
	
	return msgbox;
}

function showDialog(data, title, func){
	if (isString(data)) return showMessage(data, title, null, true, func);

    if (data.style == null) data.style = [{}];

    while (data.style.length < data.title.length) data.style.push({});

	var max = 4;
	var res = {};
	var num = data.title.length;
    var msg = "<table class='DialogTable'>"
            + "<tr v-for='(val,key,idx) in model'><td>"
            + "<input class='TextLabel' v-model='title[idx]' :size='titlesize' disabled/>"
            + "<select v-if=\"strlen(style[idx].select)>0\" v-model='model[key]' :id=\"'vue_dialog_'+idx\" :name='key' class='TextSelect'><option v-for=\"val in style[idx].select.split('|')\" :value='val' v-html='val'></option></select>"
            + "<textarea v-else-if=\"style[idx].type=='textarea'\" v-model='model[key]' @input='if(style[idx].filter)model[key]=style[idx].filter($event.currentTarget.value)' :id=\"'vue_dialog_'+idx\" :name='key' :size='style[idx].size' :type=\"style[idx].type||'text'\" :readonly='style[idx].readonly' :maxlength='style[idx].maxlength' :placeholder='style[idx].placeholder' class='TextArea' style='resize:none'/>"
			+ "<input v-else v-model='model[key]' @input='if(style[idx].filter)model[key]=style[idx].filter($event.currentTarget.value)' :id=\"'vue_dialog_'+idx\" :name='key' :size='style[idx].size' :type=\"style[idx].type||'text'\" :readonly='style[idx].readonly' :maxlength='style[idx].maxlength' :placeholder='style[idx].placeholder' autocomplete='off' class='TextField'/>"
			+ "</td><td v-if='style[idx].minlength' class='MustTagTd'>*</td></tr></table>";

	for (var i = 0; i < num; i++){
		var tmp = getTextSize(data.title[i]);
		if (tmp > max) max = tmp;
	}

	data['titlesize'] = max + 2;

    res['msgbox'] = showMessage(msg, title, null, true, function(flag){
		for (var i = 0; i < num; i++){
			var elem = getCtrl('vue_dialog_' + i);
			dispatch(elem, 'input');
			if (flag && data.style[i].minlength && strlen(elem.value) < data.style[i].minlength){
				if (strlen(elem.value) > 0){
					setMessageErrorText(data.title[i] + (lang == 'CN' ? '长度不足' : ' format error'), elem);
				}
				else{
					setMessageErrorText(data.title[i] + (lang == 'CN' ? '不能为空' : ' required'), elem);
				}
				return false;
			}
		}
        if (func) return func(flag);
    }, null, data);

    for (var i = 0; i < num; i++){
		var elem = getCtrl('vue_dialog_' + i);
		if (data.style[i].type == 'textarea') $(elem).height(48).prev().height(48);
		if (data.style[i].setup) data.style[i].setup(elem);
		res[elem.name] = elem;
	}

    return res;
}

function showConfirmDialog(data, title, func){
	if (isString(data)) return showConfirmMessage(data, title, func);

    if (data.style == null) data.style = [{}];

    while (data.style.length < data.title.length) data.style.push({});

	var max = 4;
	var res = {};
	var num = data.title.length;
    var msg = "<table class='DialogTable'>"
            + "<tr v-for='(val,key,idx) in model'><td>"
            + "<input class='TextLabel' v-model='title[idx]' :size='titlesize' disabled/>"
            + "<select v-if=\"strlen(style[idx].select)>0\" v-model='model[key]' :id=\"'vue_dialog_'+idx\" :name='key' class='TextSelect'><option v-for=\"val in style[idx].select.split('|')\" :value='val' v-html='val'></option></select>"
            + "<textarea v-else-if=\"style[idx].type=='textarea'\" v-model='model[key]' @input='if(style[idx].filter)model[key]=style[idx].filter($event.currentTarget.value)' :id=\"'vue_dialog_'+idx\" :name='key' :size='style[idx].size' :type=\"style[idx].type||'text'\" :readonly='style[idx].readonly' :maxlength='style[idx].maxlength' :placeholder='style[idx].placeholder' class='TextArea' style='resize:none' spellcheck='false'/>"
			+ "<input v-else v-model='model[key]' @input='if(style[idx].filter)model[key]=style[idx].filter($event.currentTarget.value)' :id=\"'vue_dialog_'+idx\" :name='key' :size='style[idx].size' :type=\"style[idx].type||'text'\" :readonly='style[idx].readonly' :maxlength='style[idx].maxlength' :placeholder='style[idx].placeholder' autocomplete='off' spellcheck='false' class='TextField'/>"
			+ "</td><td v-if='style[idx].minlength' class='MustTagTd'>*</td></tr></table>";

	for (var i = 0; i < num; i++){
		var tmp = getTextSize(data.title[i]);
		if (tmp > max) max = tmp;
	}

	data['titlesize'] = max + 2;

    res['msgbox'] = showConfirmMessage(msg, title, function(flag){
		for (var i = 0; i < num; i++){
			var elem = getCtrl('vue_dialog_' + i);
			dispatch(elem, 'input');
			if (flag && data.style[i].minlength && strlen(elem.value) < data.style[i].minlength){
				if (strlen(elem.value) > 0){
					setMessageErrorText(data.title[i] + (lang == 'CN' ? '长度不足' : ' format error'), elem);
				}
				else{
					setMessageErrorText(data.title[i] + (lang == 'CN' ? '不能为空' : ' required'), elem);
				}
				return false;
			}
		}
        if (func) return func(flag);
    }, null, true, data);

    for (var i = 0; i < num; i++){
		var elem = getCtrl('vue_dialog_' + i);
		if (data.style[i].type == 'textarea') $(elem).height(48).prev().height(48);
		if (data.style[i].setup) data.style[i].setup(elem);
		res[elem.name] = elem;
	}

    return res;
}

function isTimeout(){
	return strlen(curuser) <= 0;
}

function sessionTimeout(){
	setTimeout(function(){
		showLoginDialog(true);
	}, 10);
}

function getCurrentUser(){
	return curuser;
}

function setLoginCallback(func){
	logincallback = func;
}

function showLoginDialog(passwd){
	var msg = getHttpResult('/app/workspace/pub/userlogin.htm');

	showToastMessage(msg, null, null, null, true);
	
	if (passwd) $('#UserLoginLabel').click();
}

function setCurrentUser(user, updated){
	if (curuser = user){
		if (strlen(user) > 0) setStorage('user', user);

		if (updated){
			if (isFunction(logincallback)){
				logincallback();
			}
			else{
				window.location.reload();
			}
		}
	}
}

function isLeapYear(year){
	if (year % 4) return false;

	if (year % 400 == 0){
		if (year % 3200 == 0) return (year % 153600 == 0) ? true : false;

		return true;
	}

	return (year % 100 == 0) ? false : true;
}

function getMonthDayCount(month, leap){
	var count = -1;

	if (month <= 0 || month > 12) return -1;

	if (month == 2){
		count = leap ? 29 : 28;
	}
	else if (month <= 7){
		count = (month % 2 == 0) ? 30 : 31;
	}
	else{
		count = (month % 2 == 0) ? 31 : 30;
	}

	return count;
}

function getDateCheckCode(year, month, date){
	if (year < -999) return 1;
	if (year > 9999) return 2;
	if (month < 1) return 3;
	if (month > 12) return 4;
	if (date < 1) return 5;

	var days = getMonthDayCount(month, isLeapYear(year));
	
	if (date > days) return 6;

	return 0;
}

function setFrameStyle(top, side, main, bottom, topheight, sidewidth, bottomheight, margin){
	top = getCtrl(top);
	side = getCtrl(side);
	main = getCtrl(main);
	bottom = getCtrl(bottom);
	
	if (margin == null || margin < 0) margin = 0;
	if (topheight == null || topheight < 0) topheight = 0;
	if (sidewidth == null || sidewidth < 0) sidewidth = 0;
	if (bottomheight == null || bottomheight < 0) bottomheight = 0;

	top.style.position = 'absolute';
	top.style.top = margin + 'px';
	top.style.left = margin + 'px';
	top.style.right = margin + 'px';
	top.style.height = (topheight + 1)+ 'px';

	if (topheight > 0){
		top.style.display = 'block';
	}
	else{
		top.style.display = 'none';
	}

	side.style.overflow = 'auto';
	side.style.position = 'absolute';
	side.style.top = (topheight + margin + margin) + 'px';
	side.style.left = top.style.left;
	side.style.width = sidewidth + 'px';
	side.style.bottom = (bottomheight + margin + margin) + 'px';

	if (sidewidth > 0){
		side.style.display = 'block';
	}
	else
	{
		side.style.display = 'none';
	}

	main.style.overflow = 'auto';
	main.style.position = 'absolute';
	main.style.top = side.style.top;
	main.style.left = (sidewidth + margin + margin) + 'px';
	main.style.right = top.style.right;
	main.style.bottom = side.style.bottom;

	bottom.style.position = 'absolute';
	bottom.style.left = top.style.left;
	bottom.style.right = top.style.right;
	bottom.style.bottom = margin + 'px';
	bottom.style.height = bottomheight + 'px';

	if (bottomheight > 0){
		bottom.style.display = 'block';
	}
	else{
		bottom.style.display = 'none';
	}	
}

function DBConnect(name, maxsz){
	if (maxsz == null) maxsz = 1024 * 1024;

	this.db = openDatabase(name, '1.0', name, maxsz);
	
	this.drop = function(tabname){
		this.execute('DROP TABLE ' + tabname);
	};
	
	this.clear = function(tabname){
		this.execute('DELETE FROM ' + tabname);
	};

	this.query = function(sqlcmd, param, callback, errcallback){
		if (isFunction(param)){
			errcallback = callback;
			callback = param;
			param = [];
		}

		this.execute(sqlcmd, param, function(conn, result){
			var list = [];
			for (var i = 0; i < result.rows.length; i++) list[i] = result.rows.item(i);
			callback(list);
		}, errcallback);
	};
	
	this.execute = function(sqlcmd, param, callback, errcallback){
		if (isFunction(param)){
			errcallback = callback;
			callback = param;
			param = [];
		}

		this.db.transaction(function(conn){
			conn.executeSql(sqlcmd, param, callback, errcallback);
		});
	};
}

function PieChart(elem, title, series){
	elem = getCtrl(elem);

	var group = [];
	var chart = echarts.init(elem);
	var label = {
		formatter: '{title|{b}\n{d}%}',
		rich: {
			title: {
				align: 'center',
				padding: [2, 0]
			}
		}
	};

	for (var i = 0; i < series.length; i++){
		var item = series[i];
		group.push(item.name);
		if (item.label == null) item.label = label;
	}

	chart.setOption({
		title: {x: 'center', text: title},
		legend: {data: group, top: 'bottom'},
		series: [{type: 'pie', radius: '55%', data: series}],
		emphasis: {
            itemStyle: {
            	shadowBlur: 10,
                shadowOffsetX: 0,
                shadowColor: 'rgba(0, 0, 0, 0.5)'
            }
        },
		tooltip: {
			padding: [0],
			trigger: 'item',
			borderRadius: '0px',
			backgroundColor: 'none',
			formatter: function(data){
				return '<tips>' + data.value + '</tips>';
			}
		}
	});

	this.chart = chart;
	this.elem = elem;
}

function BarChart(elem, title, xaxis, series){
	elem = getCtrl(elem);

	var data = [];
	var group = [];
	var color = [];
	var chart = echarts.init(elem);
	var colorlist = ['#91C7AE', '#D48265', '#61A0A8', '#2F4554', '#D53A35'];

	for (var i = 0; i < series.length; i++){
		var arr = [];
		var item = series[i];
		var list = item.list;
		group.push(item.group);
		color.push(item.color ? item.color : colorlist[i]);
		for (var j = 0; j < list.length; j++) arr.push(list[j]);
		data.push({data: arr, type: 'bar', name: item.group, itemStyle: {normal: {color: item.color}}});
	}

	var option = {
		title: {x: 'center', text: title},
		legend: {data: group, top: 'bottom'},
        xAxis: {data: xaxis},
        yAxis: {},
        series: data,
		tooltip: {
			padding: [0],
			trigger: 'item',
			borderRadius: '0px',
			backgroundColor: 'none',
			formatter: function(data){
				return '<tips>' + data.value + '</tips>';
			}
		}
	}

	chart.setOption(option);

	this.option = option;
	this.color = color;
	this.chart = chart;
	this.elem = elem;
}

function LineChart(elem, title, xaxis, series){
	elem = getCtrl(elem);

	var data = [];
	var group = [];
	var color = [];
	var chart = echarts.init(elem);
	var colorlist = ['#91C7AE', '#D48265', '#61A0A8', '#2F4554', '#D53A35'];

	for (var i = 0; i < series.length; i++){
		var arr = [];
		var item = series[i];
		var list = item.list;
		group.push(item.group);
		color.push(item.color ? item.color : colorlist[i]);
		for (var j = 0; j < list.length; j++) arr.push(list[j]);
		data.push({data: arr, type: 'line', name: item.group, itemStyle: {normal: {color: item.color}}});
	}

	var option = {
		title: {x: 'center', text: title},
		legend: {data: group, top: 'bottom'},
        xAxis: {data: xaxis, boundaryGap: false},
        yAxis: {},
        series: data,
		tooltip: {
			padding: [0],
			trigger: 'item',
			borderRadius: '0px',
			backgroundColor: 'none',
			formatter: function(data){
				return '<tips>' + data.value + '</tips>';
			}
		}
	}

	chart.setOption(option);

	this.min = function(val){
		option.yAxis['min'] = val;
		chart.setOption(option);
	}

	this.max = function(val){
		option.yAxis['max'] = val;
		chart.setOption(option);
	}

	this.scale = function(flag){
		option.yAxis['scale'] = flag;
		chart.setOption(option);
	}

	this.symbol = function(size){
		var vec = option.series;
		for (var i = 0; i < vec.length; i++){
			vec[i]['symbolSize'] = size;
		}
		chart.setOption(option);
	}

	this.smooth = function(flag){
		var vec = option.series;
		for (var i = 0; i < vec.length; i++){
			vec[i]['smooth'] = flag;
		}
		chart.setOption(option);
	}

	this.interval = function(gap){
		option.xAxis['axisLabel'] = {
			interval: gap
		}
		chart.setOption(option);
	}

	this.push = function(a, b, c, d, e){
		function push(idx, val){
			var vec = option.series[idx]['data'];
			if (vec.length > 0){
				if (option.series[idx]['symbolSize'] === 0){
					var item = vec[vec.length - 1];
					if (isObject(item)) item['symbolSize'] = 0;
				}
				vec.pop_front();
			}
			vec.push(val);
		}

		if (a || a == 0) push(0, a);
		if (b || b == 0) push(1, b);
		if (c || c == 0) push(2, c);
		if (d || d == 0) push(3, d);
		if (e || e == 0) push(4, d);

		chart.setOption(option);
	}

	this.option = option;
	this.color = color;
	this.chart = chart;
	this.elem = elem;
}

function GaugeChart(elem, title, maxval, minval, label){
	elem = getCtrl(elem);

	var fmt = '{value}';
	var chart = echarts.init(elem);
	var width = getWidth(elem) / 12;

	if (width > 30) width = 30;
	if (width < 10) width = 10;
	if (minval == null) minval = 0;
	if (maxval == null) maxval = minval + 100;
	if (minval == 0 && maxval == 100) fmt += '%';

	var option = {
		title: {x: 'center', text: title},
		series: [{
			min: minval,
			max: maxval,
			type: 'gauge',
			detail: {formatter: fmt},
			data:[{value: minval, name: label}],
			axisLine: {lineStyle: {width: width}}
		}]
	}

	var data = option.series[0].data[0];

	chart.setOption(option);

	this.getValue = function(){
		return data.value;
	}

	this.setValue = function(val){
		if (val != data.value){
			data.value = val;
			chart.setOption(option, true);
		}
	}

	this.option = option;
	this.chart = chart;
	this.elem = elem;
}

function SlideBar(elem, maxval, minval, height){
	var bar = getCtrl(elem);

	bar.innerHTML = "<div style='position:relative;margin:0px;display:inline-block;background:#6B6'>0</div>";

	if (minval == null) minval = 0;
	if (maxval == null) maxval = minval + 100;

	var func = null;
	var drag = bar.childNodes[0];
	var score = maxval - minval;

	if (!height) height = 14;

	bar.style.padding = '0px';
	bar.style.userSelect = 'none';
	bar.style.background = '#BBB';
	bar.style.height = height + 'px';

	drag.style.top = '-2px';
	drag.style.textAlign = 'center';
	drag.style.userSelect = 'none';
	drag.style.cursor = 'default';
	drag.style.border = '1px dashed #888';
	drag.style.height = (height + 2) + 'px';
	drag.style.lineHeight = (height + 3) + 'px';
	drag.style.width = strlen(minval) <= 3 && strlen(maxval) <= 3 ? '22px' : '26px';
	
	var value = 0;
	var barwidth = bar.offsetWidth;
	var dragwidth = drag.offsetWidth;
	var slidewidth = barwidth - dragwidth + 1;

	function setValue(val){
		var pos = parseInt(slidewidth * (val - minval) / score + 0.5);

		pos += getLeft(bar);

		$(drag).offset({left: pos}).text(val);

		if (value != val){
			value = val

			if (isFunction(func)) func(val);
		}
	};

	drag.onmousedown = function(ev){
		var ev = ev || window.event;
		var str = getLeft(bar);

		if (ev.button == 0){
			var x = ev.clientX;
			var ox = getLeft(drag);
			var doconmouseup = document.onmouseup;
			var docmousemove = document.onmousemove;

			function update(dx){
				var pos = ox + dx;

				if (pos < str) pos = str;
				if (pos > str + slidewidth) pos = str + slidewidth;

				setValue(minval + parseInt((pos - str) * score / slidewidth + 0.5));
			}

		    document.onmousemove = function(ev){
		        var ev = ev || window.event;
				update(ev.clientX - x);
			};

			document.onmouseup = function(){
		        document.onmousemove = docmousemove;
				document.onmouseup = doconmouseup;
				var ev = ev || window.event;
				update(ev.clientX - x);
		    };
		}
	};

	this.setValue = setValue;

	this.getValue = function(){
		return value;
	}

	this.change = function(fun){
		func = fun;
	}
};

function AlbumBox(elem, cx, cy, img, url){
	elem = $.pack(elem);

	var str = '';
	var page = 0;
	var id = 'AlbumBox' + getSequence();
	var html = "<table id='" + id + "'><tr><td style='height:16px'></td></tr><tr><td align='left'>";
	
	for (var i = 0; i < img.length; i++){
		str = str + "<span class='Point" + id + "'></span>";
	}
	
	html += "<img id='LastPage" + id + "' src='/res/img/left.png' /></td><td align='right'>"
	html += "<img id='NextPage" + id + "' src='/res/img/right.png' /></td></tr>"
	html += "<tr><td colspan='2' style='height:16px;text-align:center;vertical-align:middle'>" + str + "</td></tr></table>";
	
	elem.append(html);
	
	var widget = $('.Point' + id);
	
	widget.css('width', '12px').css('height', '12px').css('display', 'inline-block');
	widget.css('border-radius', '8px').css('margin', '0px 8px');

	widget = $('#' + id);
	
	var showImage = function(idx){
		if (idx == null) idx = 0;
		else if (idx >= img.length) idx = 0;
		else if (idx < 0) idx = img.length - 1;
		
		page = idx;
		widget.hide();
		widget.css('width', cx).css('height', cy);
		widget.css('background-image', 'url(' + img[page] + ')');
		widget.css('background-position', 'center');
		widget.css('background-repeat', 'no-repeat');
		widget.css('background-size', '100% 100%');
		widget.fadeIn();
		
		$('.Point' + id).css('background', '#888');
		$('.Point' + id + ':eq(' + page + ')').css('background', '#E00');
	}
	
	$('.Point' + id).css('background', '#888').click(function(e){
		e.stopPropagation();
		showImage($(this).index());
	}).hover(function(){
		if ($(this).index() != page){
			$(this).css('background', '#888');
		}
	}).mouseup(function(){
		if ($(this).index() != page){
			$(this).css('background', '#888');
		}
	}).mouseout(function(){
		if ($(this).index() != page){
			$(this).css('background', '#888');
		}
	}).mousedown(function(){
		if ($(this).index() != page){
			$(this).css('background', '#888');
		}
	});
	
	var lastImage = function(){
		showImage(page - 1);
	}
	
	var nextImage = function(){
		showImage(page + 1);
	}
	
	widget.click(function(){
		if (url && url[page]){
			window.open(url[page]);
		}
	});

	widget.css('#NextPage', 'background-image 0.5s ease-in-out');
	
	$('#LastPage' + id).css('opacity', '0.2').click(function(event){
		event.stopPropagation();
		lastImage();
	}).mousedown(function(){
		$(this).css('opacity', '0.2');
	}).mouseup(function(){
		$(this).css('opacity', '0.8');
	});
	
	$('#NextPage' + id).css('opacity', '0.2').click(function(event){
		event.stopPropagation();
		nextImage();
	}).mousedown(function(){
		$(this).css('opacity', '0.3');
	}).mouseup(function(){
		$(this).css('opacity', '0.8');
	});
	
	widget.hover(function(){
		$('#LastPage' + id).css('opacity', '0.8');
		$('#NextPage' + id).css('opacity', '0.8');
	}).mouseup(function(){
		$('#LastPage' + id).css('opacity', '0.8');
		$('#NextPage' + id).css('opacity', '0.8');
	}).mouseleave(function(){
		$('#LastPage' + id).css('opacity', '0.3');
		$('#NextPage' + id).css('opacity', '0.2');
	});
	
	this.showImage = showImage;
	this.nextImage = nextImage;
	this.lastImage = lastImage;
	this.getWidget = function(){
		return widget;
	}
}

function ContextMenu(parent, menus, click){
	if (isString(menus)) menus = menus.split(',');

	var view = $.pack(parent).append("<div class='ContextMenuDialog'></div>").children('div:last');

	menus.forEach(function(item){
		view.append('<div>' + item + '</div>');
	});

	view.children('div').click(function(){
		click($(this).text(), getContextMenuAttach());
	});

	this.view = view;

	this.bind = function(elem){
		bindContextMenu(elem, view);
	}
}

function MenuBar(elem, text, icon, group, closable){
	if (closable == null) closable = true;

	function getLine(text, icon, menu){
		icon = icon ? "<td style='width:16px'><img style='width:100%;height:16px;padding-top:3px' src='" + icon + "'/></td>" : "";
		menu = menu && closable ? "<td style='text-aling:right;font-size:10px'><div style='float:right;inline-block;margin-right:6px' class='transform'>&gt;</div></td>" : "<td></td>";
		return "<table style='width:100%;text-align:left'><tr>" + icon + "<td><div style='padding:5px;font-size:0.95rem'>" + text + "</div></td>" + menu + "</tr></table>";
	}

	elem = $.pack(elem).append('<div></div>').children('div:last');

	if (closable){
		elem.append("<div style='cursor:default;padding:2px;user-select:none'>" + getLine(text, icon, true) + "</div><div style='display:none'></div>");
	}
	else{
		elem.append("<div style='cursor:default;padding:2px;user-select:none'>" + getLine(text, icon, true) + "</div><div></div>");
	}

	var tag = elem.find('.transform');
	var bar = elem.children('div:first');
	var list = elem.children('div:last');

	var self = this;
	var click = null;
	var color = '#FFF';
	var curitem = null;
	var curcolor = null;
	var hoveritem = null;
	var barcolor = '#586068';
	var listcolor = '#343640';
	var hovercolor = '#222222';
	var selectcolor = '#FFFFFF';

	bar.css('background-color', barcolor).css('color', color);
	list.css('background-color', listcolor).css('color', color);

	if (group) group.push(this);

	function open(){
		list.css('display', 'block');
		tag.css('transform', 'rotate(90deg)');
		if (group){
			group.forEach(function(item){
				if (item != self) item.close();
			});
		}
	}

	function close(){
		if (closable){
			list.css('display', 'none');
			tag.css('transform', 'rotate(0deg');
		}
	}

	function select(item, click){
		if (item){
			if (curitem == null || item != curitem[0]){
				item = $.pack(item);
				list.children('div').css('background-color', listcolor).css('color', color);
				curitem = item.css('background-color', selectcolor).css('color', barcolor);
				if (click) click(item);
				if (group){
					group.forEach(function(bar){
						if (item != bar.select()) bar.unselect();
					});
				}
			}
		}
		return curitem ? curitem : null;
	}

	bar.click(function(){
		if (list.css('display') == 'none'){
			if (click) click(true);
			open();
		}
		else{
			if (click) click(false);
			close();
		}
	});

	this.add = function(text, icon, click){
		list.append("<div style='cursor:default;padding-left:22px'>" + getLine(text, icon) + "</td></tr></table></div>");
		var item = list.children('div:last').click(function(){
			select(this, click);
		}).hover(function(){
			if (curitem) curcolor = curitem.css('background-color');
			list.children('div').css('background-color', listcolor);
			hoveritem = $(this).css('background-color', hovercolor);
			if (curitem) curitem.css('background-color', curcolor);
		}, function(){
			if (curitem) curcolor = curitem.css('background-color');
			list.children('div').css('background-color', listcolor);
			if (curitem) curitem.css('background-color', curcolor);
		});
		item.menubar = self;
		return item;
	}

	this.open = open;
	this.close = close;
	this.select = select;

	this.unselect = function(){
		if (curitem){
			curitem.css('background-color', listcolor).css('color', color);
			curitem = null;
		}
	}

	this.click = function(func){
		click = func;
	}

	this.color = function(data){
		if (data){
			if (data.color) color = data.color;
			if (data.barcolor) barcolor = data.barcolor;
			if (data.listcolor) listcolor = data.listcolor;
			if (data.hovercolor) hovercolor = data.hovercolor;
			if (data.selectcolor) selectcolor = data.selectcolor;

			bar.css('background-color', barcolor).css('color', color);
			list.css('background-color', listcolor).css('color', color);
		}

		return {color: color, barcolor: barcolor, listcolor: listcolor, hovercolor: hovercolor, selectcolor: selectcolor};
	}

	this.clear = function(){
		list.children().remove();
	}
}

function QueryWidget(elem, desc, title, func, width){
	elem = $.pack(elem);

	if (width == null) width = 48;

	elem.html("<table style='width:100%'><tr>"
		+ "<td><input class='TextField' autocomplete='off' style='width:100%;padding:8px;box-shadow:none;border-radius:0px;box-sizing:border-box' type='text' placeholder='" + desc + "'/></td>"
		+ "<td style='width:" + width + "px'><input class='TextButton' style='width:100%;padding:8px;box-shadow:none;border-radius:0px;box-sizing:border-box' value='" + title + "' readonly/></td>"
		+ "</tr></table>");

	var list = elem.find('input');
	var text = list.first();

	this.button = list.last().css('margin', '0px').click(function(){
		func(text);
	});

	this.text = text.keydown(function(e){
		if (e.which == 13) func(text);
	});

	return text;
}

function RecordListView(elem, path, vmdata, paramfunc){
	var id = 'RecordListView' + getSequence();

	$.pack(elem).append("<div id='" + id + "'></div>");

	$('#' + id).html(getHttpResult('/app/workspace/pub/recordlist.htm'));

	if (vmdata['list'] == null) vmdata['list'] = [];
	if (vmdata['button'] == null) vmdata['button'] = [];
	if (vmdata['filter'] == null) vmdata['filter'] = {};
	if (vmdata['pagenum'] == null) vmdata['pagenum'] = 0;
	if (vmdata['pagecount'] == null) vmdata['pagecount'] = 0;

	if (vmdata['pagesize'] == null){
		var height = $(document).height();
		if (height < 500){
			vmdata['pagesize'] = 10;
		}
		else if (height < 800){
			vmdata['pagesize'] = 15;
		}
		else{
			vmdata['pagesize'] = 20;
		}
	}

	if (paramfunc == null){
		paramfunc = function(){
			return {};
		};
	}

	var view = getVue(id, vmdata);
	var nextpage = $('#' + id + ' .NextPage').children().css('margin-right', '3px');
	var lastpage = $('#' + id + ' .LastPage').children().css('margin-right', '5px');
	var firstpage = $('#' + id + ' .FirstPage').children().css('margin-right', '3px');
	var frontpage = $('#' + id + ' .FrontPage').children().css('margin-right', '3px');

	var pagenumtext = $('#' + id + ' .PageNumText');
	var pagecountlabel = $('#' + id + ' .PageCountLabel').children().css('margin-right', '4px');

	firstpage.click(function(){
		vmdata.pagenum = 0;
		loadRecord(true);
	});

	lastpage.click(function(){
		vmdata.pagenum = vmdata.pagecount - 1;
		loadRecord(true);
	});

	nextpage.click(function(){
		vmdata.pagenum += 1;
		loadRecord(true);
	});

	frontpage.click(function(){
		vmdata.pagenum -= 1;
		loadRecord(true);
	});

	function page(num, flag){
		if (num >= vmdata.pagecount) num = vmdata.pagecount - 1;
		if (num < 0) num = 0;

		pagenumtext.val(num + 1);
		vmdata.pagenum = num;
		loadRecord(flag);
	}

	pagenumtext.blur(function(){
		var val = pagenumtext.val();

		if (strlen(val) == 0){
			pagenumtext.val(vmdata.pagenum + 1);
		}
		else{
			var num = parseInt(val);

			if (num != vmdata.pagenum + 1) page(num - 1);
		}
	}).keydown(function(e){
		if (e.which == 13) pagenumtext.blur();
	});

	function setLabelText(text){
		pagecountlabel.attr('size', getTextSize(text)).val(text);
	}

	function updatePageButtonStatus(){
		if (vmdata.pagecount == null || vmdata.pagecount < 0) return pagenumtext.parent().hide();

		pagenumtext.parent().show();

		firstpage.attr('disabled', 'disabled');
		frontpage.attr('disabled', 'disabled');
		nextpage.attr('disabled', 'disabled');
		lastpage.attr('disabled', 'disabled');

		if (vmdata.pagecount <= 0){
			setLabelText('第0/0页');
			pagenumtext.val('');
		}
		else{
			if (vmdata.pagenum >= vmdata.pagecount) vmdata.pagenum = vmdata.pagecount - 1;

			var num = vmdata.pagenum + 1;

			if (vmdata.pagenum > 0){
				frontpage.removeAttr('disabled');
				firstpage.removeAttr('disabled');
			}
			
			if (num < vmdata.pagecount){
				nextpage.removeAttr('disabled');
				lastpage.removeAttr('disabled');
			}

			setLabelText('第' + num + '/' + vmdata.pagecount + '页');
			pagenumtext.val(num);
		}

		if (vmdata.pagecount > 999){
			pagenumtext.attr('size', '5');
		}
		else if (vmdata.pagecount > 99) {
			pagenumtext.attr('size', '3');
		}
		else{
			pagenumtext.attr('size', '2');
		}
	}

	function loadRecord(flag){
		var param = paramfunc();

		param['pagenum'] = vmdata.pagenum;
		param['pagesize'] = vmdata.pagesize;

		if (flag) showToastMessage('正在加载数据...');

		getHttpResult(path, param, function(data){
			if (flag) hideToastBox();

			if (data.code == XG_TIMEOUT){
				if (flag) sessionTimeout();
			}
			else if (data.code < 0){
				if (flag) showToast('加载数据失败');
			}
			else{
				if (data.list == null) data.list = [];

				if (flag && data.list.length == 0) showToast('没有数据记录');

				if (vmdata.check) vmdata.check(data);

				vmdata.pagecount = data.pagecount;
				vmdata.list = data.list;

				updatePageButtonStatus();
			}
		}, flag);
	}

	this.reload = loadRecord;
	this.view = $('#' + id);
	this.data = vmdata;
	this.page = page;
	this.vue = view;

	this.update = function(check){
		if (check || check == null){
			if (isFunction(check)) check(vmdata);
			if (vmdata.check) vmdata.check(vmdata);
		}
		view.$forceUpdate();
	}

	this.remove = function(item){
		var arr = vmdata.list;
		var len = vmdata.list.length;

		if (isObject(item)){
			for (var i = 0; i < len; i++){
				if (item == arr[i]){
					arr.splice(i, 1);
					view.$forceUpdate();
					return true;
				}
			}
		}
		else{
			if (item >= 0 && item < len){
				arr.splice(item, 1);
				view.$forceUpdate();
				return true;
			}
		}

		return false;
	};

	if (path){
		loadRecord(true);
	}
	else{
		updatePageButtonStatus();
	}
}

function UploadFileWidget(elem, title, height, size){
	var self = this;
	var func = null;
	var choose = null;
	var FileView = null;
	var UploadButton = null;
	var id = 'UploadFileWidget' + getSequence();

	str = "<div><input type='file' id='" + id + "FileUpload'/><input class='FileUploadButton' id='" + id + "UploadButton' onfocus='this.blur()' readonly/><input class='TextField' id='" + id + "UploadPreviewFile' onfocus='this.blur()' readonly/></div>";
	
	$.pack(elem).append(str);
	
	str = "<div id='" + id + "UploadFileName'></div><div id='" + id + "UploadFileType'></div>"
	str += "<div id='" + id + "UploadFileSize'></div><progress id='" + id + "UploadProgress'></progress>";

   	appendCtrl(createCtrl('div', id + 'UploadInfoDiv'));

	$('#' + id + 'UploadInfoDiv').addClass('UploadInfoDiv').html(str);
	$('#' + id + 'UploadProgress').addClass('UploadProgress');
	FileView = $('#' + id + 'UploadPreviewFile');
	UploadButton = $('#' + id + 'UploadButton');
	setLabelText(id + 'UploadButton', title);
	$('#' + id + 'FileUpload').hide();

	if (strlen(height) > 0){
		UploadButton.height(height).css('line-height', height);
		FileView.height(height);
	}

	var showUploadButton = function(){
		$('#' + id + 'UploadInfoDiv').hide();
		$('#' + id + 'FileUpload').val('');
	}
	
	FileView.click(function(){
		$('#' + id + 'FileUpload').click();
	});

	UploadButton.click(function(){
		$('#' + id + 'FileUpload').click();
	});

	if (size == null) size = 1024 * 1024;
				
	$('#' + id + 'FileUpload').change(function(){
		var sz = 0;
		var file = getCtrl(id + 'FileUpload').files[0];
		
		self.data = null;

		$(this).val('');

		if (file){
			if (file.size > size){
				if (getLanguage() == 'CN'){
					showToast('文件大小不能超过' + size / 1024 + 'KB');
				}
				else{
					showToast('picture size can not exceed ' + size / 1024 + 'KB');
				}
			}
			else{
				if (choose == null || choose(file)){
					self.data = window.URL.createObjectURL(file);

					sz = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';

					if (strlen(type = file.type) == 0) type = 'text/plain';

					if (type.length > 24) type = type.substr(0, 22) + '...';

					if (getLanguage() == 'CN'){
						getCtrl(id + 'UploadFileName').innerHTML = '名称：' + file.name;
						getCtrl(id + 'UploadFileType').innerHTML = '类型：' + type;
						getCtrl(id + 'UploadFileSize').innerHTML = '大小：' + sz;
					}
					else{
						getCtrl(id + 'UploadFileName').innerHTML = 'NAME: ' + file.name;
						getCtrl(id + 'UploadFileType').innerHTML = 'TYPE: ' + type;
						getCtrl(id + 'UploadFileSize').innerHTML = 'SIZE: ' + sz;
					}
					
					var width = FileView.parent().width();
					var widget =  getCtrl(id + 'UploadInfoDiv');
					
					if (width < 180) width = 180;
					if (width > 360) width = 360;

					widget.style.top = (getTop(UploadButton[0]) + UploadButton.height() + 2) + 'px';
					widget.style.left = getLeft(UploadButton[0]) + 'px';
					widget.style.width = width + 'px';
					widget.style.display = 'block';

					var fd = new FormData();
					var xhr = new XMLHttpRequest();

					fd.append(id + 'FileUpload', file);

					xhr.addEventListener('error', function(evt){
						if (func) func();
						showUploadButton();
					}, false);
					
					xhr.addEventListener('abort', function(evt){
						if (func) func();
						showUploadButton();
					}, false);

					xhr.upload.addEventListener('progress', function(evt){
						var percent = 100;
						var progress = getCtrl(id + 'UploadProgress');

						if (evt.lengthComputable){
							percent = Math.round(evt.loaded * 100 / evt.total);
						}
						progress.innerText = percent + '%';
						progress.value = percent / 100.0;
					}, false);

					xhr.addEventListener('load', function(evt){
						var data = eval('(' + evt.target.responseText + ')');
						
						if (data.code <= 0){
							if (func) func(data);
						}
						else{
							var reader = new FileReader();

							reader.readAsDataURL(file);
							FileView.val(file.name);
							if (func) func(data);
						}

						setTimeout(showUploadButton, 1000);
					}, false);

					xhr.open('POST', '/RecvFile');
					xhr.send(fd);
				}
			}
		}
	});

	this.label = FileView;
	this.button = UploadButton;
	this.change = function(fun){
		choose = fun;
	}
	this.callback = function(fun){
		func = fun;
	}
	this.setFilter = function(filter){
		$('#' + id + 'FileUpload').attr('accept', filter);
	}
	this.getFileData = function(){
		return getCtrl(id + 'FileUpload').files[0];
	}
}

function UploadImageWidget(elem, title, height, size, local){
	var self = this;
	var func = null;
	var ImageView = null;
	var UploadButton = null;
	var id = 'UploadImageWidget' + getSequence();
	var str = "<div><input type='file' id='" + id + "FileUpload'/><input class='FileUploadButton' id='" + id + "UploadButton' onfocus='this.blur()' readonly/><span><input id='" + id + "UploadPreviewImage' style='cursor:default' readonly/></span></div>";

	$.pack(elem).append(str);

	str = "<div id='" + id + "UploadFileName'></div><div id='" + id + "UploadFileType'></div>"
	str += "<div id='" + id + "UploadFileSize'></div><progress id='" + id + "UploadProgress'></progress>";

   	appendCtrl(createCtrl('div', id + 'UploadInfoDiv'));

	$('#' + id + 'UploadInfoDiv').addClass('UploadInfoDiv').html(str);
	$('#' + id + 'UploadProgress').addClass('UploadProgress');
	ImageView = $('#' + id + 'UploadPreviewImage');
	UploadButton = $('#' + id + 'UploadButton');
	setLabelText(id + 'UploadButton', title);
	ImageView.addClass('UploadPreviewImage');
	$('#' + id + 'FileUpload').hide();
	
	if (strlen(height) > 0){
		UploadButton.height(height).css('line-height', height);
		ImageView.height(height).css('width', height);
	}
	
	var showUploadButton = function(){
		$('#' + id + 'UploadInfoDiv').hide();
		$('#' + id + 'FileUpload').val('');
	}
	
	UploadButton.click(function(){
		$('#' + id + 'FileUpload').click();
	});

	if (size == null) size = 1024 * 1024;
		
	$('#' + id + 'FileUpload').change(function(){
		var sz = 0;
		var file = getCtrl(id + 'FileUpload').files[0];
		
		self.data = null;

		$(this).val('');

		if (file){
			var ext = getFileExtname(file.name);

			if (ext.length <= 0 || 'bmp/png/gif/ico/jpg/jpeg'.indexOf(ext) < 0){
				if (getLanguage() == 'CN'){
					showToast('图片仅限于[bmp/png/gif/jpg/ico]格式');
				}
				else{
					showToast('picture format[bmp/png/gif/jpg/ico]');
				}
			}
			else{
				if (file.size > size){
					if (getLanguage() == 'CN'){
						showToast('图片大小不能超过' + size / 1024 + 'KB');
					}
					else{
						showToast('picture size can not exceed ' + size / 1024 + 'KB');
					}
				}
				else{
					self.data = window.URL.createObjectURL(file);
					
					sz = (Math.round(file.size * 100 / 1024) / 100).toString() + 'KB';
					
					if (getLanguage() == 'CN'){
						getCtrl(id + 'UploadFileName').innerHTML = '名称：' + file.name;
						getCtrl(id + 'UploadFileType').innerHTML = '类型：' + file.type;
						getCtrl(id + 'UploadFileSize').innerHTML = '大小：' + sz;
					}
					else{
						getCtrl(id + 'UploadFileName').innerHTML = 'NAME: ' + file.name;
						getCtrl(id + 'UploadFileType').innerHTML = 'TYPE: ' + file.type;
						getCtrl(id + 'UploadFileSize').innerHTML = 'SIZE: ' + sz;
					}

					function updateView(){
						var reader = new FileReader();
							
						reader.onload = function(e){
							var img = new Image();
	
							img.src = this.result;

							img.onload = function(){
								var canvas = document.createElement('canvas');
								var ctx = canvas.getContext('2d');
								var cx = 32;
								var cy = 32;

								if (height && height.indexOf('px') > 0){
									cx = cy = height.replace('px', '');

									if (cx < 32) cx = cy = 32;
								}

								canvas.width = cx;
								canvas.height = cy;
								ctx.drawImage(img, 0, 0, cx, cy);

								ImageView.css('background-image', 'url(' + canvas.toDataURL('image/png') + ')');
							}
						}

						reader.readAsDataURL(file);
					}

					if (local){
						updateView();

						if (func) func({code: file.size, url: file.name});

						return true;
					}

					var widget =  getCtrl(id + 'UploadInfoDiv');
					
					widget.style.top = (getTop(UploadButton[0]) + UploadButton.height() + 2) + 'px';
					widget.style.left = getLeft(UploadButton[0]) + 'px';
					widget.style.display = 'block';

					var fd = new FormData();
					var xhr = new XMLHttpRequest();

					fd.append(id + 'FileUpload', file);

					xhr.addEventListener('error', function(evt){
						if (func) func();
						showUploadButton();
					}, false);
					
					xhr.addEventListener('abort', function(evt){
						if (func) func();
						showUploadButton();
					}, false);

					xhr.upload.addEventListener('progress', function(evt){
						var percent = 100;
						var progress = getCtrl(id + 'UploadProgress');

						if (evt.lengthComputable){
							percent = Math.round(evt.loaded * 100 / evt.total);
						}
						progress.innerText = percent + '%';
						progress.value = percent / 100.0;
					}, false);

					xhr.addEventListener('load', function(evt){
						var data = eval('(' + evt.target.responseText + ')');
						
						if (data.code > 0) updateView();

						if (func) func(data);

						setTimeout(showUploadButton, 1000);
					}, false);

					xhr.open('POST', '/RecvFile');
					xhr.send(fd);
				}
			}
		}
	});

	$('#' + id + 'FileUpload').attr('accept', 'image/*');

	this.image = ImageView;
	this.button = UploadButton;
	this.callback = function(fun){
		func = fun;
	}
	this.setFilter = function(filter){
		$('#' + id + 'FileUpload').attr('accept', filter);
	}
	this.getFileData = function(){
		return getCtrl(id + 'FileUpload').files[0];
	}
}

function SelectImgeWidget(elem, title, height, size){
	var func = null;
	var self = this;
	var ImageView = null;
	var UploadButton = null;
	var id = 'SelectImgeWidget' + getSequence();

	str = "<div><input type='file' id='" + id + "FileUpload'/><table><tr><td><input class='FileUploadButton' id='" + id + "UploadButton' onfocus='this.blur()' readonly/></td><td><input id='" + id + "UploadPreviewImage' onfocus='this.blur()' readonly/></td></tr></table></div>";
	
	$.pack(elem).append(str);

	ImageView = $('#' + id + 'UploadPreviewImage');
	UploadButton = $('#' + id + 'UploadButton');
	setLabelText(id + 'UploadButton', title);
	ImageView.addClass('UploadPreviewImage');
	$('#' + id + 'FileUpload').hide();
	
	if (strlen(height) > 0){
		UploadButton.height(height).css('line-height', height);
		ImageView.height(height).css('width', height);
	}
	
	showUploadButton = function(){
		$('#' + id + 'FileUpload').val('');
	}
	
	UploadButton.click(function(){
		$('#' + id + 'FileUpload').click();
	});

	if (size == null){
		size = 8 * 1024 * 1024;
	}
	else{
		size *= 1024;
	}
				
	$('#' + id + 'FileUpload').change(function(){
		var sz = 0;
		var file = getCtrl(id + 'FileUpload').files[0];
		
		self.data = null;

		if (file){
			var ext = getFileExtname(file.name);
			
			if (ext.length <= 0 || 'bmp/png/gif/jpg/jpeg'.indexOf(ext) < 0){
				if (getLanguage() == 'CN'){
					showToast('图片仅限于bmp/png/gif/jpg格式');
				}
				else{
					showToast('picture format[bmp/png/gif/jpg]');
				}
			}
			else{
				if (file.size > size){
					if (getLanguage() == 'CN'){
						showToast('图片大小不能超过' + size / 1024 + 'KB');
					}
					else{
						showToast('picture size can not exceed ' + size / 1024 + 'KB');
					}
				}
				else{
					self.data = window.URL.createObjectURL(file);
					
					ImageView.css('background-image', 'url(' + self.data + ')');

					if (func) func(self);
				}
			}
		}
	});

	this.image = ImageView;
	this.button = UploadButton;
	this.callback = function(fun){
		func = fun;
	}
	this.getFileData = function(){
		return getCtrl(id + 'FileUpload').files[0];
	}
}

(function(){
	vue = Vue;

	getBrowserInfo();

	loadStyle('/res/css/widget.css');

	if (machinetype == 'MOBILE') loadStyle('/res/css/mobile.css');

	$(document).ready(function(){
		if (getBackgroundImage(document.body) == 'none') loadScript('/res/lib/background.js.gzip');
	});

	function checkLogin(){
		getHttpResult('/CheckLogin', {flag: 'C'}, function(data){
			if (data.code > 0){
				setTimeout(function(){
					setCurrentUser(data.user);
				}, 1000);

				setCurrentUser(data.user);
			}
			else if (data.code == XG_TIMEOUT){
				setCurrentUser(null);
			}
		});
	}

	checkLogin();

	setInterval(checkLogin, 10000);

	window.onresize = function(){
		for (var id in autoresizemap){
			var func = autoresizemap[id];
			if (isFunction(func)) func();
		}
	};

	document.onmouseup = function(){
		var display = $('#XG_TOAST_MODESCREEN_DIV_ID').css('display');
		
		if (display == null || display == 'none') $('#XG_TOAST_DIV_ID').fadeOut();

		if (contextmenuview){
			document.oncontextmenu = defaultcontextmenu;
			contextmenuview.style.display = 'none';
			contextmenuview = null;
		}
	};

	vue.directive('inserted', {
		inserted: function(elem){
			dispatch(elem, 'click');
		}
	});

	vue.component('v-ul', {
		props: ['id', 'title', 'option'],
		template: "<span><ul :id='id'><li v-for=\"text in option.split('|')\" v-html='text'></li></ul></span>"
	});
	
	vue.component('v-ol', {
		props: ['id', 'title', 'option'],
		template: "<span><ol :id='id'><li v-for=\"text in option.split('|')\" v-html='text'></li></ol></span>"
	});
	
	vue.component('v-icon', {
		props: ['id', 'title', 'size', 'path'],
		template: "<span @click='init' v-inserted><input class='TextLabel' :value='title' :size='getTextSize(title)' disabled/><span @click='click'><input :id='id' class='PreviewIcon' style='cursor:default' readonly/></span></span>",
		methods: {
			init : function(){
				if (strlen(this.size) == 0){
					this.size = 16;
				}
				else{
					this.size = parseInt(this.size);
				}

				if (this.size > 0) $('#' + this.id).width(this.size).height(this.size).parent().prev().height(this.size);
			},
			click : function(){
				var pick = new IconPicker(this.id, this.path);
				$('#' + this.id).blur(function(){
					pick.hide();
				});
			}
		}
	});

	vue.component('v-text', {
		props: ['id', 'size', 'type', 'title', 'readonly', 'maxlength', 'placeholder'],
		template: "<span><input class='TextLabel' :value='title' :size='getTextSize(title)' disabled/><input class='TextField' autocomplete='off' :id='id' :type='type' :size='size' :maxlength='maxlength' :readonly='readonly' :placeholder='placeholder'/></span>"
	});
	
	vue.component('v-label', {
		props: ['id', 'title'],
		template: "<span><input class='TextLabel' type='label' :value='title' :size='getTextSize(title)' :id='id' disabled/></span>"
	});
	
	vue.component('v-border', {
		props: ['size', 'radius', 'color', 'padding'],
		template: "<div :style=\"{padding:padding,display:'inline-block',borderRadius:radius,border:parseInt(size||1) + 'px solid ' + (color||'#999')}\"><slot></slot></div>"
	});
	
	vue.component('v-color', {
		props: ['id', 'title', 'value'],
		template: "<span @click='init' v-inserted><input class='TextLabel' :value='title' :size='getTextSize(title)' disabled/><span @click='click'><input :id='id' size='7' class='TextField' style='cursor:default' readonly/></span></span>",
		methods: {
			init : function(){
			},
			click : function(){
				var pick = new ColorPicker(this.id);
				$('#' + this.id).blur(function(){
					pick.hide();
				});
			}
		}
	});
	
	vue.component('v-button', {
		props: ['id', 'title'],
		template: "<span><input class='TextButton' :value='title' :size='getTextSize(title)' :id='id' onfocus='this.blur()' readonly/></span>"
	});
	
	vue.component('v-select', {
		props: ['id', 'title', 'option'],
		template: "<span @click='init' v-inserted><input class='TextLabel' :value='title' :size='getTextSize(title)' disabled/><select class='TextSelect' :id='id'><option v-for=\"(text, idx) in option.split('|')\" :value='idx' v-html='text'></option></select></span>",
		methods: {
			init : function(){
				var widget = $('#' + this.id);
				var height = widget.prev().height();
				widget.height(height).css('line-height', '17px');
				if (widget.attr('inited')){
					widget.removeAttr('inited');
				}
				else{
					setTimeout(function(){
						widget.attr('inited', 'true');
						widget.parent().click();
					}, 500);
				}
			}
		}
	});

	vue.component('v-qrcode', {
		props: ['id', 'size', 'value', 'background', 'foreground'],
		template: "<span @click='init' :id='id' :size='size' :value='value' :background='background' :foreground='foreground' v-inserted></span>",
		methods: {
			init : function(){
				var widget = $('#' + this.id);
				var size = widget.attr('size');
				if (strlen(size) == 0 || (size = parseInt(size)) <= 32) size = 32;
				widget.html('').qrcode({text: widget.val(), width: size, height: size, background: widget.attr('background'), foreground: widget.attr('foreground')});
			}
		}
	});
	
	vue.component('v-textarea', {
		props: ['id', 'title', 'height', 'readonly', 'maxlength', 'placeholder'],
		template: "<span @click='init' v-inserted><input class='TextLabel' :value='title' :size='getTextSize(title)' disabled/><textarea class='TextArea' :id='id' :maxlength='maxlength' :readonly='readonly' :placeholder='placeholder'/></span>",
		methods: {
			init : function(){
				if (strlen(this.height) == 0){
					this.height = 60;
				}
				else{
					this.height = parseInt(this.height);
				}
				$('#' + this.id).height(this.height).css('resize', 'none').prev().height(this.height);
			}
		}
	});

	vue.component('v-password', {
		props: ['id', 'size', 'type', 'title', 'readonly', 'maxlength', 'placeholder'],
		template: "<table class='TextFieldTable' @click='init' v-inserted><tr><td><input type='password' :id='id' :type='type' :size='size' :maxlength='maxlength' :readonly='readonly' :placeholder='placeholder'></td><td><img/></td></tr></table>",
		methods: {
			init : function(){
				if (this.inited) return true;

				var txt = $('#' + this.id);
				var tab = $('#' + this.id).parent().parent().parent();

				if (strlen(this.type) == 0 || this.type.toLowerCase() == 'password'){
					tab.find('img').attr('src', '/res/img/eyeclose.png');
					txt.attr('type', 'password');
				}
				else{
					tab.find('img').attr('src', '/res/img/eyeopen.png');
					txt.attr('type', 'text');
				}

				tab.find('td').css('padding', '0px').css('margin', '0px');
				tab.css('background', txt.css('background'));

				txt.focus(function(){
					tab.addClass('TextFieldTableFocus');
				}).blur(function(){
					tab.removeClass('TextFieldTableFocus');
				});

				tab.find('img').click(function(){
					if (this.src.indexOf('open') > 0){
						this.src = '/res/img/eyeclose.png';
						txt.attr('type', 'password');
					}
					else{
						this.src = '/res/img/eyeopen.png';
						txt.attr('type', 'text');
					}
				});

				this.inited = true;

				return true;
			}
		}
	});
	
	vue.component('v-textfield', {
		props: ['id', 'size', 'type', 'title', 'readonly', 'maxlength', 'placeholder'],
		template: "<table class='TextFieldTable' @click='init' v-inserted><tr><td><input type='password' :id='id' :type='type' :size='size' :maxlength='maxlength' :readonly='readonly' :placeholder='placeholder'></td><td><img src='/res/img/clear.png'/></td></tr></table>",
		methods: {
			init : function(){
				if (this.inited) return true;

				var txt = $('#' + this.id);
				var tab = $('#' + this.id).parent().parent().parent();

				tab.find('td').css('padding', '0px').css('margin', '0px');
				tab.css('background', txt.css('background'));

				txt.focus(function(){
					tab.addClass('TextFieldTableFocus');
				}).blur(function(){
					tab.removeClass('TextFieldTableFocus');
				});

				tab.find('img').click(function(){
					txt.val('');
					txt.focus();
				});

				this.inited = true;

				return true;
			}
		}
	});

	vue.component('v-datetext', {
		props: ['id', 'min', 'max', 'title', 'readonly'],
		template: "<span><input class='TextLabel' :value='title' :size='getTextSize(title)' disabled='disabled'/><input class='TextField' @click='init' type='text' :id='id' :size='10' :readonly='readonly'/></span>",
		methods: {
			init: function(){
				var dt = getDateTime().substr(0, 10);

				if ((strlen(this.min) == 0 || dt >= this.min) && (strlen(this.max) == 0 || dt <= this.max)){
					dt = true;
				}
				else{
					dt = false;
				}
				
				laydate({
					elem: '#' + this.id,
					istoday: dt,
					istime: false,
					min: this.min,
					max: this.max,
					format: 'YYYY-MM-DD',
				});
			}
		}
	});
	
	vue.component('v-datetimetext', {
		props: ['id', 'min', 'max', 'title', 'readonly'],
		template: "<span><input class='TextLabel' :value='title' :size='getTextSize(title)' disabled='disabled'/><input class='TextField' @click='init' type='text' :id='id' :size='19' :readonly='readonly'/></span>",
		methods: {
			init: function(){
				var dt = getDateTime();
				
				if ((strlen(this.min) == 0 || dt >= this.min) && (strlen(this.max) == 0 || dt <= this.max)){
					dt = true;
				}
				else{
					dt = false;
				}
				
				laydate({
					elem: '#' + this.id,
					istoday: true,
					istime: true,
					min: this.min,
					max: this.max,
					format: 'YYYY-MM-DD hh:mm:ss',
				});
			}
		}
	});
}());